#include <stdio.h>
#include <sys/types.h>          
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <sqlite3.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>

#define N 32

#define R 1  //register
#define L 2  //login
#define Q 3  //query
#define H 4  //history

#define DATABASE "my.db"

//定义通信双方的信息结构体
typedef struct 
{
    int flag;  // 1是root用户
    int type;               
    char name[N];          
    char data[256];
}MSG;


void do_client(int acceptfd, char *ip, int port, sqlite3 *db);
void do_register(int acceptfd, MSG *msg, sqlite3 *db);
void do_login(int acceptfd, MSG *msg, sqlite3 *db);
void do_query(int acceptfd, MSG *msg, sqlite3 *db);
void do_history(int acceptfd, MSG *msg, sqlite3 *db);
int history_callback(void* arg,int f_num,char** f_value,char** f_name);
int  do_searchword(int acceptfd, MSG *msg, char word[]);
void get_date(char *date);



int main(int argc, const char *argv[])
{
    int sockfd;
    int acceptfd;
    struct sockaddr_in serveraddr;
    struct sockaddr_in clientaddr;
    int client_len;
    MSG msg;
    pid_t pid;
    sqlite3 *db;

    if(argc != 3)
    {
	printf("usage:%s serverip port.\n", argv[0]);
    }

    //打开数据库
    if(sqlite3_open(DATABASE, &db) != SQLITE_OK)
    {
	printf("%s:%s\n", __func__, sqlite3_errmsg(db));
	return -1;
    }

    //添加root用户
    char *sql = "insert or ignore into usr values('root', '1');";
    char * errmsg;
    if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    {
	printf("%s--sqliet3_exec--%s\n", __func__, errmsg);
    }

    //创建套接字
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
	perror("fail to socket:");
	return -1;
    }

    //设置端口复用
    int opt = 1;
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    //绑定
    bzero(&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    serveraddr.sin_port = htons(atoi(argv[2]));
    if(bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
    {
	perror("fail to bind:");
	return -1;
    }

    //监听
    if(listen(sockfd, 5) < 0)
    {
	perror("fail to listen:");
	return -1;
    }

    //处理僵尸进程
    signal(SIGCHLD, SIG_IGN);

    while(1)
    {
	bzero(&clientaddr, sizeof(clientaddr));
	client_len = sizeof(clientaddr);
	if((acceptfd = accept(sockfd, (struct sockaddr*)&clientaddr, &client_len)) < 0)
	{
	    perror("fail to accept:");
	    return -1;
	}

	//打印客户端信息
	printf("client ip:%s, port:%d\n",inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));

	if((pid = fork()) < 0)
	{
	    perror("fail to fork");
	    return -1;
	}
	else if(pid == 0)
	{
	    //子进程
	    close(sockfd);
	    //处理客户端具体信息	
	    do_client(acceptfd, inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port), db);
	}
	else
	{
	    //父进程
	    close(acceptfd);
	}
    }

    return 0;
}

void do_client(int acceptfd, char *ip, int port, sqlite3 *db)
{
    MSG msg;
    int len;

    while(1)
    {
	len = recv(acceptfd, &msg, sizeof(msg), 0);
	if(len < 0)
	{
	    printf("%s--recv--%s\n", __func__, strerror(errno));
	    exit(0);
	}
	else if(len == 0)
	{
	    printf("client ip:%s port:%d exit \n", ip, port);
	    close(acceptfd);
	    exit(0);
	}
	else
	{
	    printf("type:%d\n", msg.type);
	    switch(msg.type)
	    {
		case R:
		    do_register(acceptfd, &msg, db);
		    break;
		case L:
		    do_login(acceptfd, &msg, db);
		    break;
		case Q:
		    do_query(acceptfd, &msg, db);
		    break;
		case H:
		    do_history(acceptfd, &msg, db);
		    break;
		default:
		    strcpy(msg.data, "Invalid data msg->type!");
		    if(send(acceptfd, &msg, sizeof(MSG), 0) < 0)
		    {
			printf("%s--send--%s\n", __func__, strerror(errno));
			exit(0);
		    }
	    }
	}	    
    }

}

//注册
void do_register(int acceptfd, MSG *msg, sqlite3 *db)
{
    char * errmsg;
    char sql[128];

    //拼接sql语句
    sprintf(sql, "insert into usr values('%s', '%s');", msg->name, msg->data);
    printf("%s\n", sql);

    if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    {
	printf("%s--sqliet3_exec--%s\n", __func__, errmsg);
	strcpy(msg->data, "usr name already exist.");
    }
    else
    {
	printf("client register ok!\n");
	strcpy(msg->data, "OK!");
    }

    if(send(acceptfd, msg, sizeof(MSG), 0) < 0)
    {
	printf("%s--send--%s\n", __func__, strerror(errno));
    }

    return ;

}

//登录
void do_login(int acceptfd, MSG *msg, sqlite3 *db)
{
    char sql[128] = {};
    char *errmsg;
    int nrow;
    int ncloumn;
    char ** resultp;

    //判断root用户
    if(strncmp(msg->name, "root", strlen(msg->name)) == 0)
    {
	msg->flag = 1;
    }

    sprintf(sql, "select * from usr where name = '%s' and pass = '%s';", msg->name, msg->data);
    printf("%s\n", sql);

    if(sqlite3_get_table(db, sql, &resultp, &nrow, &ncloumn, &errmsg) != SQLITE_OK)
    {
	printf("%s--sqlite3_get_table--%s", __func__, errmsg);
	strcpy(msg->data, "Login failed.");
    }

    bzero(msg->data, sizeof(msg->data));
    nrow == 1 ? strcpy(msg->data, "OK") : strcpy(msg->data, "usr/passwd wrong");

    if(send(acceptfd, msg, sizeof(MSG), 0) < 0)
    {
	printf("%s--send--%s\n", __func__, strerror(errno));
    }
}

//获得时间
void get_date(char *date)
{   
    time_t t;
    struct tm *tp;

    time(&t);

    //进行时间格式转换
    tp = localtime(&t);

    sprintf(date, "%d-%d-%d %d:%d:%d", tp->tm_year + 1900, tp->tm_mon+1, tp->tm_mday, 
	    tp->tm_hour, tp->tm_min , tp->tm_sec);
}


//查询
void do_query(int acceptfd, MSG *msg, sqlite3 *db)
{
    FILE *fp;
    char temp[512] = {0};
    int len;
    char flag[512];
    char *errmsg;

    if((fp = fopen("dict.txt", "r")) == NULL)
    {
	printf("%s--fopen--%s\n", __func__, strerror(errno));
	strcpy(msg->data, "Failed to open dict.txt");
	if(send(acceptfd, msg, sizeof(MSG), 0) < 0)
	{
	    printf("%s--send--%s\n", __func__, strerror(errno));
	}
    }

    len = strlen(msg->data);
    strcpy(flag, msg->data);
    while(fgets(temp, sizeof(temp), fp) != NULL)
    {
	if(strncmp(temp, msg->data, len) == 0 && temp[len] == ' ')
	{
	    strncpy(msg->data, temp, strlen(temp));
	    break;
	}
    }
    fclose(fp);

    //没找到单词
    if(len == strlen(msg->data))
    {
	strcpy(msg->data, "Not found!");
    }
    else  //找到单词了,将单词插入数据库
    {
	char date[128] = {0};
	char sql[128] = {0};
	get_date(date);

	sprintf(sql, "insert into record values ('%s', '%s', '%s');", msg->name,  date, flag);
	printf("%s\n", sql);

	if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
	{
	    printf("%s--sqlite3_exec--%s\n", __func__, errmsg);
	}

    }

    if(send(acceptfd, msg, sizeof(MSG), 0) < 0)
    {
	printf("%s--send--%s\n", __func__, strerror(errno));
    }
}

int history_callback(void* arg,int f_num,char** f_value,char** f_name)
{
    int acceptfd;
    MSG msg;

    acceptfd = *((int *)arg);

    sprintf(msg.data, "%s -- %s -- %s", f_value[0], f_value[1], f_value[2]);

    if(send(acceptfd,&msg, sizeof(MSG), 0) < 0)
    {
	printf("%s--send--%s\n", __func__, strerror(errno));
    }

    return 0;
}

//历史记录
void do_history(int acceptfd, MSG *msg, sqlite3 *db)
{
    char sql[128] = {0};
    char *errmsg;

    //判断root用户
    if(msg->flag == 1)
    {
	sprintf(sql, "select name, word, date from record order by name asc;");
    }
    else
    {
	sprintf(sql, "select name, word, date from record where name = '%s';", msg->name);
    }

    if(sqlite3_exec(db, sql, history_callback, (void *)&acceptfd, &errmsg) != SQLITE_OK)
    {
	printf("%s--sqlite3_exec--%s\n", __func__, errmsg);
	return ;
    }

    msg->data[0] = '\0';  //做个标识已读完

    if(send(acceptfd, msg, sizeof(MSG), 0) < 0)
    {
	printf("%s--send--%s\n", __func__, strerror(errno));
    }
}







